// 这是对所有链接的封装，也就是对fd的封装，解决了历史缓存数据的问题。
#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include "InetAddr.hpp"

// #include"EpollServer.hpp"
//extern 声明
class Reactor; // 声明方式有三种这是其中一种，

// vesion1-这是使用回调函数去区分不同的模式
//  class Connection;//
//  using func_t = std::function<void(std::shared_ptr<Connection>)>;

// 每一个Connection都有一个文件描述符，那么fd分为listensockfd和普通fd如何正确封装！
// 让对fd的处理方式采用同一种方式
// 描述一个链接
class Connection
{
public:
    // Connection(int sockfd)
    //     : _sockfd(sockfd), _events(0)
    // {
    // }
    Connection()
        : _sockfd(gdefaultsockfd), _events(0)
    {
    }
    int Fd()
    {
        return _sockfd;
    }
    // 把客户端信息写进来
    void SetPeerInfo(const InetAddr &peer_addr)
    {
        _peer_addr = peer_addr;
    }
    void SetSockfd(int sockfd)
    {
        _sockfd = sockfd;
    }
    // 提供set方法初始化回调方法
    // void InitCB(func_t recver, func_t sender, func_t excepter)
    // {
    //     // 模块化注册对应的方法
    //     _recver = recver;
    //     _sender = sender;
    //     _excepter = excepter;
    // }
    // void CallRecv(connection_t conn)
    // {
    //     if (_recver != nullptr)
    //         _recver(conn);
    // }
    // void CallSend(connection_t conn)
    // {
    //     if (_sender != nullptr)
    //         _sender(conn);
    // }
    void SetOwner(Reactor *owner)
    {
        _owner = owner;
    }
    void SetEvents(uint32_t events)
    {
        _events = events;
    }
    void AppendString(const std::string &in) // 把数据缓存到自己的应用层的缓冲区里。
    {
        _inbuffer += in;
    }
    void AppendOutString(const std::string &out) // 把数据缓存到自己的应用层的缓冲区里。
    {
        _outbuffer += out;
    }
    bool IsOutBufferEmpty()
    {
        return _outbuffer.empty();
    }
    void DisCardOutString(int n)
    {
        // 剔除已经发送的
        _outbuffer.erase(0, n);
    }
    std::string &OutString() // for test——TODO
    {
        return _outbuffer;
    }
    std::string &InString() // for test——TODO
    {
        return _inbuffer;
    }
    Reactor *GetOwner()
    {
        return _owner;
    }
    void Close()
    {
        if(_sockfd>=0)
        {
            close(_sockfd);
        }

    }
    uint32_t GetEvents() { return _events; }
    ~Connection() {}

public:
    // vesion-3使用继承的方法去实现不同的模式。
    virtual void Sender() = 0;
    virtual void Recver() = 0;
    virtual void Excepter() = 0;

protected://这里设置成保护权限的原因是要让派生类可以访问，同时不让飞类对象成员访问。
    int _sockfd;//要管理文件那么fd肯定是要有的。
    std::string _inbuffer;  // 用string充当缓冲区，暂存在这里。因为不能直接在OS内核中去拿流式缓冲区判断。
    std::string _outbuffer; // 发送缓冲区，暂时存在这里。
    InetAddr _peer_addr;    // 对应远端的某一个客户端

    // //vesion-2不暴露用函数去设置
    // // 加入回调方法，去取代用基类和派生类的写法
    // func_t _recver;   // 接受
    // func_t _sender;   // 发送
    // func_t _excepter; // 异常处理
    // // 这样写的好处，方便理解，拓展简单TAT。

    // 添加一个服务器的连接
    Reactor *_owner; // 指向的服务器,为了可以通过Connection去调用服务器中的epollser变量去操作Epoll模型。

    // 我关心的事件。
    uint32_t _events; // 我这个Connection关心的事件。

    // //vesion-1
    // public://接口暴露出来，因为不想接着去封装了。
    //    // 加入回调方法，去取代用基类和派生类的写法
    //     func_t _recver;   // 接受
    //     func_t _sender;   // 发送
    //     func_t _excepter; // 异常处理
    //     // 这样写的好处，方便理解，拓展简单TAT。

    //     // 添加一个服务器的连接
    //     EpollServer *_owner;//指向的服务器,为了可以通过Connection去调用服务器中的epollser变量去操作Epoll模型。

    //拓展
    uint64_t timestamp;//设置一个接口——更新时间，重新获取时间戳，再IOService时，买一次发和收时，都调用这个接口去检查这个链接是否活跃。超时检查也是设置这个然后去遍历所有的_connection。
};

// class Factory//工厂
// {
// public:
//     static std::shared_ptr<Connection> BuildConnection(int fd,uint32_t events,func_t r,func_t w,func_t e)
//     {
//         auto conn = std::make_shared<Connection>(fd);
//         conn->SetEvents(events);
//         conn->InitCB(r,w,e);
//         return conn;
//     }
// };

// 不这么写，换种方式
//  class ListenConnection:public Connection
//  {

// };

// class NormalConnection:public Connection
// {

// };